package edu.buffalo.cse.cse486_586.simpledht.bean;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import android.util.Log;

import edu.buffalo.cse.cse486_586.simpledht.config.Configuration;
import edu.buffalo.cse.cse486_586.simpledht.config.MasterConfiguration;
import edu.buffalo.cse.cse486_586.simpledht.config.Node;
import edu.buffalo.cse.cse486_586.simpledht.entity.MyPackage;
import edu.buffalo.cse.cse486_586.simpledht.service.SendingThread;
import edu.buffalo.cse.cse486_586.util.AppUtil;
import edu.buffalo.cse.cse486_586.util.CommonUtil;

public class MessageBean {
	private static final String TAG = "MessageBean";

	/*
	 * pkg format: 1/--/console_port
	 */
	public MyPackage generateJoinPkg(int localPort) {
		MyPackage pkg = new MyPackage(AppUtil.PACKAGE_JOIN,
				String.valueOf(localPort));
		return pkg;
	}

	/*
	 * pkg format: 2/--/port_number/--/predecessor/--/successor
	 */
	public MyPackage generateSetUpPkg(Node node) {
		MyPackage pkg = new MyPackage(AppUtil.PACKAGE_SET_UP, node.toString());
		return pkg;
	}

	/*
	 * pkg format: 3/--/port_number
	 */
	public MyPackage generateReadyPkg() {
		int port = Configuration.getInstance().getNode().getNodePort();
		return new MyPackage(AppUtil.PACKAGE_READY, String.valueOf(port));
	}

	/*
	 * pkg format: 4
	 */
	public MyPackage generateResetPkg() {
		return new MyPackage(AppUtil.PACKAGE_RESET, "");
	}

	/*
	 * pkg format: 5
	 */
	public MyPackage generateStatablePkg() {
		return new MyPackage(AppUtil.PACKAGE_STABLE, "");
	}

	/*
	 * pkg format: 7/--/sender_port/--/key
	 */
	public MyPackage generateLookUpPkg(String key) {
		Node n = Configuration.getInstance().getNode();

		return new MyPackage(AppUtil.PACKAGE_LOOK_UP, n.getNodePort()
				+ AppUtil.DELIMITER + key);
	}

	/*
	 * @String str, the joining node's port process the Join message
	 * 
	 * @return the Node object, leave the predecessor and successor empty
	 */
	public Node processJoinMessage(String str) {
		Node n = null;
		if (CommonUtil.isNumeric(str)) {
			n = new Node();
			n.setNodePort(Integer.valueOf(str));
			n.setHashKey(CommonUtil.genHash(str));
			n.setRedirPort(CommonUtil.getRedirectPort(Integer.valueOf(str)));
		}

		return n;
	}

	/*
	 * @String str, the node setting-up message
	 * 
	 * @return the Node object, fill all properties
	 */
	public void processSetUpMessage(String str) {
		Configuration config = Configuration.getInstance();
		String tokens[] = str.split(AppUtil.DELIMITER);
		if (CommonUtil.isNumeric(tokens[1]) && CommonUtil.isNumeric(tokens[2])
				&& CommonUtil.isNumeric(tokens[3])) {
			Node localNode = config.getNode();
			localNode.setHashKey(CommonUtil.genHash(tokens[1]));
			localNode.setNodePort(Integer.parseInt((tokens[1])));
			localNode.setPredecessor(Integer.parseInt(tokens[2]));
			localNode.setSuccessor(Integer.parseInt(tokens[3]));
			int redirPort = CommonUtil.getRedirectPort(Integer
					.parseInt(tokens[1]));
			localNode.setRedirPort(redirPort);
		}
	}

	/*
	 * add node into the container of Master Configuration object
	 * 
	 * @parameter Node, new joining node
	 * 
	 * @return boolean, true we all ready receive all JOIN_MESSAGE from node,
	 * other wise false
	 */
	public boolean addNodeToList(Node n) {
		String key = CommonUtil.genHash(String.valueOf(n.getNodePort()));
		MasterConfiguration masterConfig = MasterConfiguration.getInstance();
		if (!masterConfig.getNodeList().containsKey(key)) {
			masterConfig.addNode(n);
		}
		return masterConfig.getNodeList().size() >= AppUtil.numDev;
	}

	/*
	 * send the Set Up Message to all alive Node
	 */
	public void sendSetUpMessage() {
		Map<String, Node> map = MasterConfiguration.getInstance().getNodeList();
		List<Node> nodeList = new ArrayList<Node>(map.values());
		// this should never happen, just in case;
		if (nodeList.isEmpty())
			return;
		// if more than 1 node in system
		if (nodeList.size() > 1) {
			int length = nodeList.size();
			for (int i = 0; i < nodeList.size(); i++) {
				Node node = nodeList.get(i);

				if (i == 0) {
					node.setPredecessor((nodeList.get(length - 1).getNodePort()));
				} else {
					node.setPredecessor((nodeList.get(i - 1).getNodePort()));
				}
				if (i == (length - 1)) {
					node.setSuccessor(nodeList.get(0).getNodePort());
				} else {
					node.setSuccessor(nodeList.get(i + 1).getNodePort());
				}
				// send setting-up message to each node
				MessageBean mb = new MessageBean();
				MyPackage pkg = mb.generateSetUpPkg(node);
				Thread t = new Thread(new SendingThread(AppUtil.EMULATOR_IP,
						node.getRedirPort(), pkg.toString()));
				t.start();
			}
		} else {
			Log.d(TAG, "set none");
			nodeList.get(0).setPredecessor(AppUtil.NONE_NODE);
			nodeList.get(0).setSuccessor(AppUtil.NONE_NODE);
			MessageBean mb = new MessageBean();
			MyPackage pkg = mb.generateSetUpPkg(nodeList.get(0));
			Thread t = new Thread(new SendingThread(AppUtil.EMULATOR_IP,
					nodeList.get(0).getRedirPort(), pkg.toString()));
			t.start();
		}
	}
}
